use actix_session::Session;
use actix_web::{
    post,
    web::{self, Data, Json},
    HttpResponse,
};
use serde_derive::{Deserialize, Serialize};

use crate::schema::user::dsl::*;
use crate::{db::models::User, DbPool};
use diesel::{prelude::*, update};

use diesel::{dsl::exists, insert_into, select};

use crate::{api::Page, schema::user};

#[derive(serde::Serialize, Deserialize)]
pub struct LoginReq {
    username: String,
    password: String,
}

#[derive(Debug, Serialize)]
pub struct LoginResp {
    role: String,
}

#[post("/login")]
pub async fn login(
    session: Session,
    request: web::Json<LoginReq>,
    db: Data<DbPool>,
) -> HttpResponse {
    let req: LoginReq = request.0;
    let user_data = web::block(move || {
        let mut conn = db.get().unwrap();
        let the_user: Result<User, _> = user
            .filter(username.eq(&req.username))
            .first::<User>(&mut conn);
        match the_user {
            Ok(u) => Some(u),
            _ => None,
        }
    })
    .await;
    match user_data.unwrap() {
        Some(mut u) => {
            if u.password.ne(&req.password) {
                return HttpResponse::Unauthorized().body("密码错误");
            }
            let json_str = serde_json::to_string(&mut u).unwrap();
            let _ = session.insert("user", json_str);
            HttpResponse::Ok().json(u)
        }
        _ => HttpResponse::Unauthorized().body("账号不存在"),
    }
}

#[post("/logout")]
pub async fn logout(session: Session) -> Json<()> {
    session.clear();
    Json(())
}

#[derive(Debug, Serialize, Deserialize)]
pub struct UpdatePasswordReq {
    password: String,
    new_password: String,
    renew_password: String,
}

#[post("/update_password")]
pub async fn update_password(
    db: Data<DbPool>,
    request: web::Json<UpdatePasswordReq>,
    session: Session,
) -> HttpResponse {
    let req = request.0;
    if req.new_password.ne(&req.renew_password) {
        return HttpResponse::BadRequest().body("两次输入的密码不一致");
    }
    let s_user = session.get::<String>("user").unwrap();
    if let Some(ustr) = s_user {
        let mut the_user = serde_json::from_str::<User>(&ustr).unwrap();
        if req.password.ne(&the_user.password) {
            return HttpResponse::BadRequest().body("旧密码不正确");
        }
        let data = web::block(move || {
            let mut conn = db.get().unwrap();
            the_user.password = req.new_password;
            println!("update user: {:?}", the_user);
            let result = update(user.filter(user::id.eq(the_user.id)))
                .set((
                    user::username.eq(the_user.username),
                    user::password.eq(the_user.password),
                    user::role.eq(the_user.role),
                ))
                .execute(&mut conn);
            match result {
                Ok(d) => d,
                _ => 0,
            }
        })
        .await;
        match data.unwrap() {
            0 => HttpResponse::BadRequest().body("名称已存在"),
            _ => HttpResponse::Ok().json(true),
        }
    } else {
        return HttpResponse::Unauthorized().body("更新密码失败");
    }
}

#[post("/update")]
async fn update_user(db: Data<DbPool>, request: web::Json<User>) -> HttpResponse {
    let req = request.0;
    let data = web::block(move || {
        let mut conn = db.get().unwrap();
        let exists: Result<bool, diesel::result::Error> = select(exists(
            user.filter(user::username.eq(&req.username).and(user::id.ne(&req.id))),
        ))
        .get_result(&mut conn);
        if let Ok(s) = exists {
            if s {
                return 0;
            }
        }
        let result: Result<usize, _> = update(user.filter(user::id.eq(req.id)))
            .set((
                user::username.eq(req.username),
                user::password.eq(req.password),
                user::role.eq(req.role),
            ))
            .execute(&mut conn);
        match result {
            Ok(d) => d,
            _ => 0,
        }
    })
    .await;
    match data.unwrap() {
        0 => HttpResponse::BadRequest().body("名称已存在"),
        _ => HttpResponse::Ok().json(true),
    }
}

#[derive(Debug, serde::Deserialize)]
pub struct DeleteProjectReq {
    id: i32,
}

#[post("/delete")]
async fn delete_user(db: Data<DbPool>, request: web::Json<DeleteProjectReq>) -> HttpResponse {
    let req = request.0;
    let data = web::block(move || {
        let mut conn = db.get().unwrap();
        let result = diesel::delete(user.filter(user::id.eq(req.id))).execute(&mut conn);
        match result {
            Ok(d) => d,
            _ => 0,
        }
    })
    .await;
    match data.unwrap() {
        0 => HttpResponse::BadRequest().body("未找到记录"),
        _ => HttpResponse::Ok().json(true),
    }
}

#[post("/create")]
async fn create_user(db: Data<DbPool>, request: web::Json<User>) -> HttpResponse {
    let req = request.0;
    let data = web::block(move || {
        let mut conn = db.get().unwrap();

        let exists: Result<bool, diesel::result::Error> =
            select(exists(user.filter(user::username.eq(&req.username)))).get_result(&mut conn);
        if let Ok(s) = exists {
            if s {
                return 0;
            }
        }
        let result = insert_into(user).values(&req).execute(&mut conn);
        match result {
            Ok(d) => d,
            _ => 0,
        }
    })
    .await;
    match data.unwrap() {
        0 => HttpResponse::BadRequest().body("名称已存在"),
        _ => HttpResponse::Ok().json(true),
    }
}

#[derive(Debug, serde::Deserialize)]
pub struct PageUserReq {
    page: i64,
    size: i64,
    keyword: String,
}

const ROLE_SUPPER: i32 = 2;

const SIZE_MAX: i64 = 50000000000;
const SIZE_INVERSE: i64 = -1;


#[post("/page")]
pub async fn page_user(db: Data<DbPool>, request: web::Json<PageUserReq>) -> Json<Page<User>> {
    let req = request.0;
    let data = web::block(move || {
        let mut conn = db.get().unwrap();
        let mut size = req.size;
        if req.size.eq(&SIZE_INVERSE) {
            size = SIZE_MAX;
        }
        let data: Result<Vec<User>, _> = user
            .filter(
                user::username
                    .like(format!("%{}%", req.keyword))
                    .and(user::role.ne(ROLE_SUPPER)),
            )
            .limit(size)
            .offset((req.page - 1) * size)
            .load::<User>(&mut conn);
        let c: Result<i64, _> = user
            .select(diesel::dsl::count(user::id))
            .filter(
                user::username
                    .like(format!("%{}%", req.keyword))
                    .and(user::role.ne(ROLE_SUPPER)),
            )
            .first(&mut conn);
        match data {
            Ok(d) => Page {
                total: c.unwrap(),
                content: d,
            },
            _ => Page {
                total: 0,
                content: vec![],
            },
        }
    })
    .await;
    Json(data.unwrap())
}
